//           Copyright Daniel Goertzen 2007.
//  Distributed under the Boost Software License, Version 1.0.
//     (See accompanying file LICENSE_1_0.txt or copy at
//           http://www.boost.org/LICENSE_1_0.txt)

/////////////////////////////
//
// eipp_packet.h
//
// This file provides send and receive functions compatible with the
// erlang port packet protocol.  See open_port() in the erlang kernel
// "erlang module".
//


#ifndef EIPP_PACKET_H
#define EIPP_PACKET_H

#include "eipp.h"
#include <limits>
#include <arpa/inet.h>

namespace eipp
{

	inline uint8_t hton(const uint8_t d) {return d;}
	inline uint16_t hton(const uint16_t d) { return htons(d);}
	inline uint32_t hton(const uint32_t d) { return htonl(d);}
	inline uint8_t ntoh(const uint8_t d) {return d;}
	inline uint16_t ntoh(const uint16_t d) { return ntohs(d);}
	inline uint32_t ntoh(const uint32_t d) { return ntohl(d);}


	template<typename T>
	ostream & send_packet_generic(ostream &ss, spbinary_t data)
	{
		size_t len=data->size();
		if(len > std::numeric_limits<T>::max()) throw bad_match("payload too large for protocol");
		T plen=hton((T)len);
		ss.write((char*)&plen,sizeof(T));
		ss.write(&(*data)[0], len);
		return ss;
	}

	template<typename T>
	spbinary_t receive_packet_generic(istream &ss)
	{
		T plen;
		ss.read((char*)&plen,sizeof(T));
		plen=ntoh(plen);
		spbinary_t data(new binary_t);
		data->resize(plen);
		ss.read(&(*data)[0], plen);
		return data;
	}

	ostream &send1(ostream &ss, spbinary_t data) { return send_packet_generic<uint8_t>(ss,data); }
	ostream &send2(ostream &ss, spbinary_t data) { return send_packet_generic<uint16_t>(ss,data); }
	ostream &send4(ostream &ss, spbinary_t data) { return send_packet_generic<uint32_t>(ss,data); }
	spbinary_t receive1(istream &ss) { return receive_packet_generic<uint8_t>(ss); }
	spbinary_t receive2(istream &ss) { return receive_packet_generic<uint16_t>(ss); }
	spbinary_t receive4(istream &ss) { return receive_packet_generic<uint32_t>(ss); }





} //namespace eipp

#endif //EIPP_PACKET_H
